#!/usr/bin/python

# nextbusloader.py: Load stops from NextBus

# Copyright 2011 Portland Transport

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#   http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# self.stops should be an array of GTFS Stop objects; they shall contain the
# code avl_id (even if it's the same as the stop_id or stop_tag). Remember,
# you (or your colleagues) have to access this data from Javascript.

# all _getStopsFrom... should return this format

# Authors:
# Matt Conway: main code

import agencyloader
from optparse import OptionParser
from nextbus import *
from time import sleep
import cPickle as pickle

class NextBusLoader(agencyloader.AgencyLoader):
    def _getStopsFromNextBus(self):
        stops = dict()

        # If the user wants to used saved data, let them
        if self.options.picklefile:
            return pickle.load(open(self.options.picklefile, 'rb'))

        # If not, take the long walk of shame
        else:
            routes = get_all_routes_for_agency(self.options.agency)
            if routes == []:
                raise NameError, 'Agency %s does not exist or has no routes defined' % self.options.agency

            # Print the time estimate
            print '''Agency %s has %s routes. Fetching them will take approximately %s minute(s). Press Ctrl-C within five seconds to abort.''' % (self.options.agency, len(routes), (len(routes)*self.options.wait)/60)
            sleep(5)
            # Open the pickle file first, in case there's a permissions
            # problem we want to know now
            outfile = open(self.options.outfile, 'wb')

            # Now, loop through the routes, populating the dictionary
            i = 1
            for route in routes:
                # Enforce time between queries
                sleep(self.options.wait)

                print 'Processing route %s/%s - %s' % (i, len(routes), route.title)

                # Get the stops on the route
                rc = get_route_config(self.options.agency, route.tag)

                # Loop over the stops
                for stop in rc.stops:
                    if self.options.usetags:
                        stopid = stop.tag
                        stoptag = stop.stop_id
                    else:
                        stopid = stop.stop_id
                        stoptag = stop.tag

                    # Check if the stop ID is in the database
                    if not stops.has_key(stopid):
                        # If there's no tag, print a warning, but add it anyhow
                        # (not sure if this is the best behavior)
                        if stop.tag == '' or stop.tag == None:
                            print 'Warning: Stop %s (%s) on route %s has no tag. Adding anyhow.' % (stop.stop_id, stop.title, route.tag)

                        # Add the stop to the database
                        # routes is populated later
                        it = dict(
                            stop_id = stopid,
                            avl_stop_id = stop.tag, # Should always be 
                            # stop.tag,
                            # because we use predictionsForMultiStops to load
                            # the data, and it only supports tags.
                            stop_desc = '',
                            position = None,
                            location_type = 0, # No stations in NextBus
                            stop_lat = stop.latitude,
                            stop_lon = stop.longitude,
                            stop_code = stoptag,
                            direction = stop.direction_tag,
                            stop_name = stop.title,
                            routes = [],
                            zone_id = None
                            )
                        stops[stopid] = it
                        
                    # Closes if not stops...
                    # Now, add this route to the route list
                    rurl = self.options.route_url
                    # If it isn't None, we need to do a replace
                    if rurl:
                        rurl = rurl.format(route=route.tag, 
                                           routelong=route.title,
                                           agency=self.options.agency)

                    stops[stopid]['routes'].append(
                        dict(route_type=self.options.route_type,
                             route_url=rurl,
                             avl_route_id = route.tag,
                             route_id = route.tag,
                             route_long_name=route.title,
                             route_short_name=route.tag))
                        
                        
                i += 1
            pickle.dump(stops.values(), outfile)
            outfile.close()
            
            return stops.values()

    # For agencies without Public GTFS, e.g. AC Transit
    def loadAllStopsNextBusOnly(self):
        self.stops = self._getStopsFromNextBus()

        self.agency = dict(
            agency_name = self.options.agency,
            avl_service = 'NextBus',
            avl_options = dict()
            )
        if self.options.usetags:
            self.agency['avl_options']['tags_as_ids'] = True

    loadAllStops = loadAllStopsNextBusOnly


# Can pass in parser with some opts already defined
# Pass in the subclassed class
def main(parser=OptionParser(), loaderClass=NextBusLoader):
    parser.add_option('-t', '--nextbus-timeout', dest='wait', type='int',
                      help='Time (seconds) to wait between requests to NextBus.',
                      metavar='SECS',
                      default=10)

    parser.add_option('--route-type', dest='route_type', type='int',
                         help='''Set the GTFS route_type value for single-mode
    transit systems. Possible values are 0-7, see the GTFS docs for types.''',
                         metavar='TYPE', default=None)

    parser.add_option('--route-url', dest='route_url', type='string',
                         help='''Set the route URL. {route} will be replaced with
    the route short number, {routelong} will be replaced with the route full name,
    and {agency} will be replaced with the NextBus agency tag''',
                         metavar='URL', default=None)

    parser.add_option('-l', '--load-file', dest='picklefile', type='string',
                      help='Where the NextBus stop data is saved.',
                      metavar='FILE',
                      default=None)

    parser.add_option('-o', '--out-file', dest='outfile', type='string',
                      help='Where the NextBus stop data is to be saved.',
                      metavar='FILE',
                      default='nextbus.pcl')

    parser.add_option('--use-tags', dest='usetags',
                      help='Use stop tags rather than stop IDs as unique.',
                      metavar='FILE', action='store_true',
                      default=False)

    # Yield to the upper class
    agencyloader.main(parser=parser, loaderClass=loaderClass)

if __name__ == '__main__':
    main()
